<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h3>关于函数的编译和执行顺序</h3>
		<ul>
			<li>函数必须先定义，才能被执行。因此在调用函数前，必须先确保函数的定义已经被编译或执行过</li>
			<li>使用function关键字定义的函数，会在代码执行前先编译，所以，该函数定义可以在调用该函数的语句之后</li>
			<li>但如果是将函数定义赋给了一个变量，则必须在函数被调用之前先执行该赋值</li>
			<button onclick="funcTest1()">运行例子</button>
		</ul>
		<script>
			function funcTest1(){
				var result = sum1(10, 20);		// sum1函数在后面定义，但是会在本语句执行前编译，因此可以正常调用
				result = sum2(10,20);			// sum2必须先要执行，才会具有函数定义；
			
				function sum1(i, j){
					return i+j;
				}
					
				var sum2 = function(i, j){		// 将此代码放在result = sum2(10,20)之前，才能正常运行
					return i+j;
				}
			}
		</script>
		
		<h3>动态执行代码</h3>
		<ul>
			<li>eval()可执行一个字符串形式的代码，可以动态构建执行代码，但效率较低</li>
			<button onclick="funcTest2()">运行例子</button>
		</ul>
		<script>
			function funcTest2(){
				eval("console.log('通过eval函数执行');");	// 需要在运行时编译字符串中的代码
				eval("var sum = function(i, j){return i+j;};");
				var result = sum(10, 20);
				console.log(result);
			}
		</script>
	
		<h3>call和apply</h3>
		<ul>
			<li>函数中的this到底代表谁，取决于是那个对象调用了这个函数</li>
			<li>通过call和apply，实际上就可以修改该函数内部的this对象</li>
			<li>从而可以实现：在不同类型的对象(上下文)上调用同一个函数，而不需要在这些对象或类上重复定义该函数</li>
			<li>事件处理函数一般由全局对象调用，因此该处理函数内的this一般就是指window对象</li>
			<li>call和apply区别主要在于参数的传递形式</li>
			<button onclick="funcTest3()">运行例子</button>
			<script>
				var message = "global";
				var obj = {
					message : "object"
				};
				function sayHello(){
					// 下列代码必须要写this.message。如果仅携程message，则会查找本地变量或全局变量message
					console.log(this.message);  // 该this到底代表谁，必须根据sayHello函数的调用者而定
				}
				function funcTest3(){
					var message = "funcTest3";
					sayHello.apply(obj);		// 通过obj对象调用sayHello函数。因此sayHello内部的this实际上就是obj对象
					sayHello.apply(window);		// 通过window对象调用sayHello
					sayHello.apply(this);		// 注意，funcTest3中的this实际上是funcTest3函数的调用者，也就是window
				}
			</script>
		</ul>
	</body>
</html>
